4 常用内置函数
4.1 引言Python内置函数的价值
Python提供了丰富的内置函数,这些函数无需导入任何模块即可直接使用。在金融数据分析中,熟练掌握这些内置函数可以显著提高代码的简洁性和执行效率。
理论背景:Batteries Included哲学
Python的设计哲学之一是”Batteries Included”(自带电池),这意味着标准库提供了丰富的功能,使得开发者可以快速完成常见任务,而无需重复造轮子。内置函数是这一哲学的极致体现。
4.2 序列处理函数
4.2.1 len()获取序列长度
len()函数返回对象(字符串、列表、元组、字典等)的长度或项目个数。
时间复杂度: - 列表、元组、字符串: O(1) - 字典、集合: O(1)
# ==================== 创建数据 ====================
# 示例数据:2018年净利润排名前10位的证券公司列表
# stock是一个列表,包含10个证券公司名称字符串
# 方括号[]用于创建列表,元素用逗号分隔
stock = ["中信证券", "国泰君安", "海通证券", "华泰证券", "广发证券", # 前5家公司
"招商证券", "申万宏源", "国信证券", "中信建投", "中国银河"] # 后5家公司
# ==================== 获取列表长度 ====================
# len()函数返回列表的元素个数
# num_companies变量存储公司总数
num_companies = len(stock) # 计算列表长度,结果是10
# f-string格式化输出,{num_companies}会被替换为变量值
print(f"证券公司数量: {num_companies}") # 输出: 证券公司数量: 10
# ==================== 应用场景:检查数据完整性 ====================
# expected_count定义期望的公司数量
expected_count = 10 # 期望有10家公司
# if语句进行条件判断,len(stock)获取实际数量
# ==是比较运算符,判断两边是否相等
if len(stock) == expected_count: # 如果实际数量等于期望数量
print("数据完整") # 输出提示信息
else: # 如果不相等
# f-string中可以插入多个变量
print(f"数据缺失,期望{expected_count}家,实际{len(stock)}家") # 输出缺失信息4.2.2 enumerate()枚举索引和值
enumerate()函数在遍历序列时同时返回索引和值,这在生成带序号的报告时非常有用。
语法: enumerate(iterable, start=0)
# ==================== 生成带排名的公司列表 ====================
# enumerate()函数同时返回索引和值
# stock是前面的证券公司列表
# start=1表示索引从1开始(更符合人类习惯的排名,默认从0开始)
ranked_companies = list(enumerate(stock, start=1)) # 创建(排名,公司名)元组的列表
# ==================== 输出排名信息 ====================
# 输出标题
print("2018年净利润排名前10位的证券公司:") # 打印标题
# for循环遍历ranked_companies列表
# rank接收排名(索引),company接收公司名(值)
for rank, company in ranked_companies: # 解包元组,遍历每个元素
# f-string格式化输出
# {rank:2d}表示rank占2位,不足2位右对齐
# {company}显示公司名
print(f" {rank:2d}. {company}") # 输出格式化的排名和公司名
# ==================== 输出示例 ====================
# 输出:
# 2018年净利润排名前10位的证券公司:
# 1. 中信证券
# 2. 国泰君安
# ...金融应用场景: - 生成排名报告 - 带时间戳的时间序列数据处理 - 多重列表的嵌套循环
4.2.3 sum()求和计算
sum()函数对可迭代对象进行求和,支持初始值参数。
语法: sum(iterable, start=0)
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
stock = ["中信证券","国泰君安","海通证券","华泰证券","广发证券","招商证券","申万宏源","国信证券","中信建设","中国银河"] # 定义列表stock
# 定义列表profit
profit = [98.7643,70.7004,57.7071,51.6089,46.3205,44.4626,42.4781,34.3125,31.0343,29.3174]
# 定义列表return_Q1
return_Q1 = [0.547783,0.315274,0.594318,0.383333,0.275237,0.307463,0.356265,0.617682,1.93341,0.734604]
price = [24.78,20.15,14.03,22.41,16.17,17.52,5.52,13.54,25.55,11.83] # 定义列表price
#输出列表中元素的个数
print(len(stock))
#以列表方式输出stock
print(list(enumerate(stock,start=1)))
#计算10家证券公司的净利润总和
profit_total =sum(profit)
#计算每家证券公司平均净利润
profit_average =profit_total/len(stock)
print("2018年净利润排名前10位的证券公司净利润总和(亿元)",profit_total) # 输出2018年净利润排名前10位的证券公司净利润总和(
print("2018年净利润排名前10位的证券公司净利润平均数(亿元)",round(profit_average,4)) # 输出2018年净利润排名前10位的证券公司净利润平均数
#找出最大涨幅
return_max =max(return_Q1)
#找出最小涨幅
return_min =min(return_Q1)
print("2019年1季度股价的最大涨幅",return_max) # 输出2019年1季度股价的最大涨幅
print("2019年1季度股价的最小涨幅",return_min) # 输出2019年1季度股价的最小涨幅
#将股价由小到大排序
price_sorted =sorted(price)
print(price_sorted) # 输出按价格升序排列的证券公司股价列表性能提示: 对于大型数值数组,numpy.sum()比内置sum()快得多,应优先使用。
4.3 极值函数
4.3.1 max()求最大值
max()函数返回可迭代对象的最大值或多个参数中的最大值。
# ==================== 创建数据 ====================
# 示例数据:2019年1季度股价涨跌幅
# return_Q1列表存储10只股票的季度收益率
# 数据以小数形式表示(例如0.547783表示54.7783%)
return_Q1 = [0.547783, 0.315274, 0.594318, 0.383333, 0.275237, # 前5只收益率
0.307463, 0.356265, 0.617682, 1.93341, 0.734604] # 后5只收益率
# ==================== 找出最大涨幅 ====================
# max()函数找出列表中的最大值
# return_max存储最大的收益率值
return_max = max(return_Q1) # 找出最大收益率
# f-string格式化输出
# :.2%表示格式化为百分数,保留2位小数
print(f"2019年1季度股价的最大涨幅: {return_max:.2%}") # 输出最大涨幅
# ==================== 应用场景:识别表现最佳股票 ====================
# .index()方法返回元素在列表中第一次出现的索引位置
# return_max是最大收益率值
# best_index存储最大收益率对应的索引
best_index = return_Q1.index(return_max) # 获取最大值的索引位置
# stock[best_index]通过索引获取对应的证券公司名称
best_company = stock[best_index] # 获取表现最佳的公司名
# 输出公司名和对应的涨幅
print(f"表现最佳: {best_company}, 涨幅: {return_max:.2%}") # 输出最佳表现股票
# ==================== 输出示例 ====================
# 输出: 表现最佳: 中信建投, 涨幅: 193.34%4.3.2 min()求最小值
min()函数返回可迭代对象的最小值或多个参数中的最小值。
# ==================== 找出最小涨幅 ====================
# min()函数找出列表中的最小值
# return_min存储最小的收益率值
return_min = min(return_Q1) # 找出最小收益率
# f-string格式化输出,:.2%表示百分数格式
print(f"2019年1季度股价的最小涨幅: {return_min:.2%}") # 输出最小涨幅
# ==================== 应用场景:识别风险资产 ====================
# if语句判断最小涨幅是否为负数(即下跌)
# <是比较运算符,判断左边是否小于右边
if return_min < 0: # 如果最小涨幅为负(下跌)
# .index()方法获取最小值的索引位置
worst_index = return_Q1.index(return_min) # 获取最小值索引
# 通过索引获取对应的公司名
worst_company = stock[worst_index] # 获取表现最差的公司名
# 输出警告信息,包括公司名和跌幅
print(f"注意: {worst_company}跌幅为{return_min:.2%}") # 输出风险提示补充说明:key参数
max()和min()函数支持key参数,可以自定义比较标准:
# ==================== 创建复杂数据 ====================
# stocks_info是一个列表,包含多个字典
# 每个字典存储一只股票的信息(名称、净利润、市盈率)
stocks_info = [ # 列表,包含3个字典元素
{'name': '中信证券', 'profit': 98.76, 'pe': 15.2}, # 字典1:键值对存储股票信息
{'name': '国泰君安', 'profit': 70.70, 'pe': 12.8}, # 字典2
{'name': '海通证券', 'profit': 57.71, 'pe': 18.5} # 字典3
]
# ==================== 按净利润找出最大 ====================
# max()函数的key参数指定比较标准
# lambda x: x['profit']定义匿名函数
# x是stocks_info中的每个元素(字典)
# x['profit']提取字典中'profit'键对应的值
# max会根据这个值进行比较,返回整个字典元素
most_profitable = max(stocks_info, key=lambda x: x['profit']) # 按利润找最大
# ['name']提取字典中name键的值
print(f"最盈利: {most_profitable['name']}") # 输出最盈利的公司
# ==================== 按PE比率找出最小(最便宜) ====================
# min()函数找出PE最小的股票(估值最低)
# lambda x: x['pe']定义提取pe值的函数
# PE越低通常表示股票越便宜
cheapest = min(stocks_info, key=lambda x: x['pe']) # 按PE找最小
print(f"最低PE: {cheapest['name']}") # 输出PE最低的公司4.4 排序函数
4.4.1 sorted()排序操作
sorted()函数返回排序后的新列表,原对象保持不变。
语法: sorted(iterable, key=None, reverse=False)
# ==================== 创建数据 ====================
# 示例数据:10只股票的股价(单位:元)
# price列表存储每只股票的价格
price = [24.78, 20.15, 14.03, 22.41, 16.17, 17.52, 5.52, 13.54, 25.55, 11.83]
# ==================== 升序排序 ====================
# sorted()函数返回排序后的新列表
# 默认reverse=False,升序排列(从小到大)
# 原列表price保持不变
price_sorted = sorted(price) # 按升序排序
print("股价排序(升序):") # 输出标题
print(price_sorted) # 输出排序后的列表
# ==================== 降序排序 ====================
# reverse=True参数指定降序排列(从大到小)
# 这在金融分析中常用于找出最高价
price_desc = sorted(price, reverse=True) # 按降序排序
print("\n股价排序(降序):") # 输出标题,\n表示换行
print(price_desc) # 输出降序排列的列表
# ==================== 金融应用:识别高估和低估股票 ====================
# 假设公允价值为18元,作为估值基准
fair_value = 18.0 # 设定公允价值
# 列表推导式筛选高估股票(价格>公允价值)
# p for p in price遍历每个价格
# if p > fair_value是筛选条件
# overvalued列表存储所有高估股票的价格
overvalued = [p for p in price if p > fair_value] # 筛选高估股票
# 列表推导式筛选低估股票(价格<公允价值)
# undervalued列表存储所有低估股票的价格
undervalued = [p for p in price if p < fair_value] # 筛选低估股票
# ==================== 输出统计结果 ====================
# len()函数计算列表长度,得到股票数量
print(f"\n高估股票数量: {len(overvalued)}") # 输出高估股票数量
print(f"低估股票数量: {len(undervalued)}") # 输出低估股票数量sorted() vs .sort():
| 特性 | sorted() | .sort() |
|---|---|---|
| 返回值 | 新列表 | None(原地修改) |
| 原对象 | 不变 | 改变 |
| 适用对象 | 所有可迭代对象 | 仅列表 |
| 链式操作 | 支持 | 不支持 |
# ==================== sorted():创建新列表 ====================
# prices列表包含3个价格
prices = [24.78, 20.15, 14.03] # 创建价格列表
# sorted()返回新的排序后列表,原列表不变
sorted_prices = sorted(prices) # 升序排序,返回新列表
print(f"原列表: {prices}") # 输出原列表(未改变)
print(f"新列表: {sorted_prices}") # 输出排序后的新列表
# ==================== .sort():原地修改 ====================
# .copy()方法创建列表的副本,避免修改原列表
prices_copy = prices.copy() # 复制列表
# .sort()方法直接在原列表上排序,返回None
prices_copy.sort() # 原地排序,修改列表本身
print(f"修改后: {prices_copy}") # 输出排序后的列表(已改变)
# ==================== 应用场景选择 ====================
# - 需要保留原数据:使用sorted()
# - 内存敏感:使用.sort()4.5 类型转换函数
4.5.1 int(), float(), str()类型转换
这些函数在不同数据类型之间进行转换。
# ==================== 场景1:从CSV读取的数据转换 ====================
# CSV文件读取的数据通常是字符串类型
# price_str是字符串形式的股价
price_str = "1850.50" # 字符串类型的价格
# volume_str是字符串形式的成交量
volume_str = "2500000" # 字符串类型的成交量
# ==================== 转换为数值类型 ====================
# float()函数将字符串转换为浮点数
# price现在是数值类型,可以进行数学运算
price = float(price_str) # 将"1850.50"转换为1850.5
# int()函数将字符串转换为整数
# volume现在是整数类型
volume = int(volume_str) # 将"2500000"转换为2500000
# ==================== 计算成交额 ====================
# *运算符执行乘法
# price * volume计算成交额(价格×成交量)
turnover = price * volume # 计算成交额
# f-string格式化输出,:,表示千位分隔符
# :,.0f表示带千位分隔符的浮点数,0位小数
print(f"成交额: {turnover:,.0f}元") # 输出: 4,626,250,000元
# ==================== 场景2:格式化输出 ====================
# amount是浮点数,表示金额
amount = 1234567.89 # 浮点数金额
# str()函数将数值转换为字符串
# amount_str现在是字符串类型
amount_str = str(amount) # 转换为字符串"1234567.89"
# 字符串可以用于文本拼接
print(f"成交金额: {amount_str}元") # 输出字符串
# ==================== 场景3:处理缺失值 ====================
# missing_values列表包含各种可能的缺失值表示
# 空字符串""、"N/A"、"None"、"1850.50"(有效值)
missing_values = ["", "N/A", "None", "1850.50"] # 包含缺失值的列表
# ==================== 遍历并处理缺失值 ====================
# for循环遍历列表中的每个值
for val in missing_values: # 遍历每个元素
# if语句检查是否为缺失值
# not in检查val是否不在缺失值列表中
if val not in ["", "N/A", "None"]: # 如果不是缺失值
# 转换为浮点数
price = float(val) # 转换有效值为浮点数
# 输出有效价格
print(f"有效价格: {price}") # 输出: 有效价格: 1850.5
else: # 如果是缺失值
# 输出缺失值标识
print(f"缺失值: {val}") # 输出缺失值类型4.6 四舍五入函数
4.6.1 round()数值舍入
round()函数对数值进行四舍五入。
语法: round(number, ndigits=None)
重要说明: Python 3采用”银行家舍入”(Round Half to Even)策略: - 2.5 → 2 (最近的偶数) - 3.5 → 4 (最近的偶数)
这在金融计算中可能导致意外结果。
# ==================== 计算平均净利润 ====================
# profit_total是前面计算的净利润总和
# len(stock)获取公司数量
# /计算平均值
profit_average = profit_total / len(stock) # 计算平均净利润
# ==================== 不同精度的舍入 ====================
# 输出精确值(无舍入)
print(f"精确值: {profit_average}") # 输出完整精度的平均值
# round(profit_average, 4)保留4位小数
print(f"保留4位小数: {round(profit_average, 4)}") # 保留4位小数
# round(profit_average, 2)保留2位小数
print(f"保留2位小数: {round(profit_average, 2)}") # 保留2位小数
# round(profit_average)不指定ndigits,取整
print(f"取整: {round(profit_average)}") # 取整
# ==================== 银行家舍入示例 ====================
# 输出标题
print("\n银行家舍入示例:") # \n换行
# round(2.5)按照银行家舍入规则
# 2和3都是2.5等距离的整数,选择偶数2
print(f"round(2.5) = {round(2.5)}") # 输出: 2
# round(3.5)按照银行家舍入规则
# 3和4都是3.5等距离的整数,选择偶数4
print(f"round(3.5) = {round(3.5)}") # 输出: 4
# ==================== 金融应用:建议使用Decimal模块 ====================
# Decimal模块提供精确的十进制运算
# ROUND_HALF_UP指定四舍五入(而非银行家舍入)
from decimal import Decimal, ROUND_HALF_UP # 导入Decimal和舍入模式
# Decimal('2.5')创建Decimal对象
# quantize()方法按指定格式舍入
# Decimal('1')表示整数格式
# rounding=ROUND_HALF_UP指定常规四舍五入
value = Decimal('2.5') # 创建Decimal对象
rounded = value.quantize(Decimal('1'), rounding=ROUND_HALF_UP) # 常规舍入
print(f"常规舍入: {rounded}") # 输出: 34.7 统计函数
Python 3.4+在statistics模块中提供了丰富的统计函数:
# ==================== 导入统计模块 ====================
# statistics是Python标准库的统计模块
import statistics # 导入statistics模块
# ==================== 创建示例数据 ====================
# returns列表包含8个收益率数据
# 既有正收益也有负收益
returns = [0.05, 0.03, -0.02, 0.04, 0.06, 0.02, -0.01, 0.07]
# ==================== 基本统计量计算 ====================
# statistics.mean()计算算术平均值
mean = statistics.mean(returns) # 计算平均收益率
# statistics.median()计算中位数
median = statistics.median(returns) # 计算中位数
# statistics.stdev()计算样本标准差
# 样本标准差使用n-1作为分母
stdev = statistics.stdev(returns) # 计算样本标准差
# statistics.variance()计算样本方差
# 方差是标准差的平方
variance = statistics.variance(returns) # 计算样本方差
# ==================== 输出统计结果 ====================
# f-string格式化输出,:.4f保留4位小数
print(f"算术平均: {mean:.4f}") # 输出平均值
print(f"中位数: {median:.4f}") # 输出中位数
print(f"标准差: {stdev:.4f}") # 输出标准差
print(f"方差: {variance:.4f}") # 输出方差
# ==================== 金融应用:风险收益分析 ====================
# 定义无风险利率(通常参考国债利率)
risk_free_rate = 0.02 # 无风险利率2%
# 计算超额收益(平均收益减去无风险利率)
excess_return = mean - risk_free_rate # 计算超额收益率
# 计算夏普比率(风险调整后收益指标)
# 夏普比率 = 超额收益 / 标准差
# 衡量每承担一单位风险获得的超额收益
sharpe_ratio = excess_return / stdev # 计算夏普比率
# 输出风险调整后收益指标
# :.4f保留4位小数
print(f"\n夏普比率: {sharpe_ratio:.4f}") # 输出夏普比率4.8 函数式编程工具
4.8.1 map()映射函数
map()函数将指定函数应用于可迭代对象的每个元素。
语法: map(function, iterable, ...)
# ==================== 示例1:类型转换 ====================
# price_strings列表包含字符串形式的股价
# 数据可能来自CSV或文本文件
price_strings = ["24.78", "20.15", "14.03", "22.41", "16.17"]
# ==================== 使用map进行类型转换 ====================
# map(function, iterable)将函数应用于每个元素
# float是内置函数,将字符串转换为浮点数
# price_strings是可迭代对象
# map返回迭代器,需要用list()转换为列表
price_floats = list(map(float, price_strings)) # 批量转换为浮点数
# 输出转换结果
print(f"转换结果: {price_floats}") # 输出浮点数列表
# ==================== 示例2:计算涨跌幅 ====================
# prices_old是调整前的价格列表
prices_old = [100, 105, 98, 102, 110] # 旧价格
# prices_new是调整后的价格列表
prices_new = [105, 110, 95, 108, 115] # 新价格
# ==================== 定义涨跌幅计算函数 ====================
# lambda定义匿名函数
# old, new是两个参数,代表旧价格和新价格
# (new - old) / old计算涨跌幅公式
calc_return = lambda old, new: (new - old) / old # 定义收益率计算函数
# ==================== 使用map批量计算 ====================
# map可以接受多个可迭代对象
# calc_return应用于prices_old和prices_new对应位置的元素
# 例如: calc_return(100, 105), calc_return(105, 110), ...
returns = list(map(calc_return, prices_old, prices_new)) # 批量计算收益率
# 列表推导式格式化输出
# [f'{r:.2%}' for r in returns]将每个收益率格式化为百分数字符串
print(f"涨跌幅: {[f'{r:.2%}' for r in returns]}") # 输出百分数形式的涨跌幅4.8.2 filter()过滤函数
filter()函数根据指定函数的条件筛选元素。
语法: filter(function, iterable)
# ==================== 示例1:筛选正收益股票 ====================
# all_returns列表包含多个收益率(正负都有)
all_returns = [0.05, -0.02, 0.03, -0.01, 0.04, -0.03, 0.06]
# ==================== 使用filter筛选正收益 ====================
# filter(function, iterable)根据函数条件筛选
# lambda x: x > 0定义筛选条件:收益率大于0
# filter返回迭代器,包含所有满足条件的元素
positive_returns = list(filter(lambda x: x > 0, all_returns)) # 筛选正收益
# 列表推导式格式化为百分数
# [f'{r:.2%}' for r in positive_returns]格式化每个正收益
print(f"正收益: {[f'{r:.2%}' for r in positive_returns]}") # 输出正收益列表
# ==================== 示例2:筛选高收益股票 ====================
# lambda x: x > 0.03定义条件:收益率大于3%
# 这用于找出表现优异的股票
high_returns = list(filter(lambda x: x > 0.03, all_returns)) # 筛选高收益(>3%)
print(f"高收益: {[f'{r:.2%}' for r in high_returns]}") # 输出高收益列表
# ==================== 应用场景:多条件筛选 ====================
# stocks列表包含多个字典,每个字典存储一只股票的信息
# 包括名称(name)、收益率(return)、风险(risk)
stocks = [
{'name': 'A', 'return': 0.05, 'risk': 0.10}, # 股票A:收益5%,风险10%
{'name': 'B', 'return': 0.08, 'risk': 0.15}, # 股票B:收益8%,风险15%
{'name': 'C', 'return': 0.06, 'risk': 0.08} # 股票C:收益6%,风险8%
]
# ==================== 筛选符合多条件的股票 ====================
# 筛选条件:收益>5% 且 风险<10%
# lambda s: s['return'] > 0.05 and s['risk'] < 0.10定义筛选函数
# s是每个股票字典
# s['return']和s['risk']访问对应键的值
# and逻辑运算符表示两个条件都要满足
filtered = list(filter( # 筛选符合条件的股票
lambda s: s['return'] > 0.05 and s['risk'] < 0.10, # 多条件筛选函数
stocks # 待筛选的股票列表
))
# 列表推导式提取符合条件的股票名称
print(f"符合条件的股票: {[s['name'] for s in filtered]}") # 输出: ['C']4.8.3 zip()配对函数
zip()函数将多个可迭代对象的元素配对成元组。
# ==================== 创建示例数据 ====================
# names列表存储证券公司名称
names = ["中信证券", "国泰君安", "海通证券"]
# prices列表存储对应的股价
prices = [24.78, 20.15, 14.03]
# volumes列表存储对应的成交量
volumes = [2500000, 1800000, 3200000] # 成交量单位:股
# ==================== 使用zip组合多个列表 ====================
# zip()将多个列表的对应元素配对成元组
# 例如: ("中信证券", 24.78, 2500000), ("国泰君安", 20.15, 1800000), ...
# list()将zip对象转换为列表
stock_data = list(zip(names, prices, volumes)) # 组合三个列表
# ==================== 输出股票数据 ====================
print("股票数据:") # 输出标题
# for循环遍历stock_data列表
# name, price, volume解包每个元组
for name, price, volume in stock_data: # 遍历每只股票的数据
# 计算成交额(价格×成交量)
turnover = price * volume # 计算成交额
# f-string格式化输出
# :.2f保留2位小数
# :,添加千位分隔符
print(f" {name}: 价格={price:.2f}, 成交量={volume:,}, 成交额={turnover:,.0f}")
# ==================== 应用场景1:创建字典 ====================
# zip可以用来创建字典
# dict(zip(keys, values))将两个列表转换为字典
# names作为键,prices作为值
stock_dict = dict(zip(names, prices)) # 创建股票价格字典
# 输出字典
print(f"\n价格字典: {stock_dict}") # 输出: {'中信证券': 24.78, ...}
# ==================== 应用场景2:同时遍历多个列表 ====================
print("\n按成交量排序:") # 输出标题
# sorted()对zip对象排序
# key=lambda x: x[2]指定按成交量(第3个元素)排序
# x[2]表示元组的第3个元素(成交量)
for name, price, volume in sorted(zip(names, prices, volumes), key=lambda x: x[2]):
# f-string格式化输出,:,添加千位分隔符
print(f" {name}: {volume:,}") # 输出排序后的股票4.9 综合应用实例
4.9.1 案例证券公司综合分析
# ==================== 数据准备 ====================
# companies列表存储公司名称
companies = ["中信证券", "国泰君安", "海通证券", "华泰证券", "广发证券"]
# profits列表存储净利润(亿元)
profits = [98.76, 70.70, 57.71, 51.61, 46.32] # 净利润数据
# prices列表存储股价(元)
prices = [24.78, 20.15, 14.03, 22.41, 16.17] # 股价数据
# ==================== 1. 基本统计 ====================
# sum()计算净利润总和
total_profit = sum(profits) # 净利润总额
# 计算平均净利润
avg_profit = total_profit / len(companies) # 平均净利润
# max()找出最高净利润
max_profit = max(profits) # 最高净利润
# min()找出最低净利润
min_profit = min(profits) # 最低净利润
# ==================== 输出基本统计 ====================
# "=" * 50生成50个等号的分隔线
print("=" * 50) # 输出分隔线
print("2018年净利润排名前5位证券公司分析") # 输出标题
print("=" * 50) # 输出分隔线
# 输出基本统计信息
print(f"\n【基本统计】") # 输出小节标题
print(f" 净利润总额: {total_profit:.2f}亿元") # 输出总额
print(f" 平均净利润: {avg_profit:.2f}亿元") # 输出平均值
print(f" 最高净利润: {max_profit:.2f}亿元") # 输出最大值
print(f" 最低净利润: {min_profit:.2f}亿元") # 输出最小值
# ==================== 2. 排名分析 ====================
# zip()将公司名和利润配对
# sorted()按利润排序
# key=lambda x: x[1]指定按利润(元组第2个元素)排序
# reverse=True表示降序(从大到小)
sorted_profits = sorted(zip(companies, profits), key=lambda x: x[1], reverse=True)
# 输出净利润排名
print(f"\n【净利润排名】") # 输出小节标题
# enumerate()添加排名序号,start=1从1开始
for rank, (company, profit) in enumerate(sorted_profits, 1): # 遍历排序后的数据
# f-string格式化输出
# {rank}是排名,{company}是公司名,{profit:.2f}是利润(保留2位小数)
print(f" {rank}. {company}: {profit:.2f}亿元") # 输出每条记录
# ==================== 3. 股价分析 ====================
# sorted()对股价排序
# key=lambda x: x[1]指定按股价(元组第2个元素)排序
# 默认升序(从低到高)
sorted_prices = sorted(zip(companies, prices), key=lambda x: x[1])
# 输出股价排名
print(f"\n【股价排名(从低到高)】") # 输出小节标题
# enumerate()添加排名序号
for rank, (company, price) in enumerate(sorted_prices, 1): # 遍历排序后的数据
# 输出每条记录
print(f" {rank}. {company}: {price:.2f}元") # 输出公司名和股价
# ==================== 4. 综合评价(高利润低股价) ====================
# 计算净利润股价比(类似市盈率的倒数)
# p / pr计算每元股价对应的净利润
# for p, pr in zip(profits, prices)同时遍历两个列表
# 结果是新的列表,存储每只股票的利润股价比
profit_price_ratios = [p / pr for p, pr in zip(profits, prices)] # 计算比率
# zip()将公司名和比率配对
ratios = list(zip(companies, profit_price_ratios)) # 创建元组列表
# max()找出比率最高的(最被低估)
# key=lambda x: x[1]指定按比率比较
best_ratio = max(ratios, key=lambda x: x[1]) # 找出最高比率
# 输出投资价值分析
print(f"\n【投资价值分析】") # 输出小节标题
# best_ratio[0]是公司名,best_ratio[1]是比率
# :.2f保留2位小数
print(f" 净利润/股价比最高: {best_ratio[0]} ({best_ratio[1]:.2f})") # 输出最优选择